package com.shunli.cterminal.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.examples.core.enums.ProjectCodeEnum;
import com.shunli.cterminal.entity.SystemTrafficPolicy;
import com.shunli.cterminal.enums.ConditionTypeEnum;
import com.shunli.cterminal.mapper.SystemOrderMapper;
import com.shunli.cterminal.mapper.SystemTrafficPolicyMapper;
import com.shunli.cterminal.model.bo.ProjectOrderNumBO;
import com.shunli.cterminal.model.dto.TrafficPolicyStrategyDTO;
import com.shunli.cterminal.model.res.SystemTrafficPolicyVO;
import com.shunli.cterminal.service.ISystemTrafficPolicyService;
import com.shunli.cterminal.strategy.Strategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 流量策略 服务实现类
 *
 * @author daodao
 * @since 2025-04-25 13:43:15
 */
@Slf4j
@Service
public class SystemTrafficPolicyServiceImpl extends ServiceImpl<SystemTrafficPolicyMapper, SystemTrafficPolicy> implements ISystemTrafficPolicyService {

    private static final int PARAM_K = 1;
    private static final int PARAM_B = 0;
    private static final double PARAM_R = 1.5;
    @Resource
    private SystemOrderMapper systemOrderMapper;

    @Resource
    private List<Strategy> strategyList;

    /**
     * 执行策略 结果 固定策略顺序的方式
     *
     * @param trafficPolicyStrategyDTO 上一个规则过滤后的结果
     * @param projectOrderNumMap       默认传空 用于测试计算最终的分配比例
     * @return String
     */
    @Override
    public String parse(TrafficPolicyStrategyDTO trafficPolicyStrategyDTO, Map<String, Long> projectOrderNumMap) {
        try {
            log.info("allocationProject项目方分配入参,param,{}", JSONObject.toJSONString(trafficPolicyStrategyDTO));
            String projectCode = this.allocationProject(trafficPolicyStrategyDTO, projectOrderNumMap);
            log.info("allocationProject项目方结果,projectCode,{}", projectCode);
            return projectCode;
        } catch (Exception e) {
            log.error("allocationProject项目方分配异常,msg,{}", e.getMessage(), e);
            return ProjectCodeEnum.GX.getCode();
        }
    }

    /**
     * 分配项目方
     *
     * @param trafficPolicyStrategyDTO 参数
     * @param projectOrderNumMap       订单数量
     * @return String
     */
    private String allocationProject(TrafficPolicyStrategyDTO trafficPolicyStrategyDTO, Map<String, Long> projectOrderNumMap) {
        List<SystemTrafficPolicyVO> systemTrafficPolicyVOList = this.queryPolicyList();
        log.info("allocationProject查询规则,PolicyList,{}", JSONObject.toJSONString(systemTrafficPolicyVOList));
        if (CollectionUtil.isEmpty(systemTrafficPolicyVOList)) {
            return ProjectCodeEnum.GX.getCode();
        }
        // 求交集的结果
        Set<SystemTrafficPolicyVO> andList = new HashSet<>(systemTrafficPolicyVOList);
        // 求并集的结果
        Set<SystemTrafficPolicyVO> orList = new HashSet<>(systemTrafficPolicyVOList);
        Set<SystemTrafficPolicyVO> orListResult = new HashSet<>();
        for (Strategy strategy : strategyList) {
            if (StrUtil.equals(ConditionTypeEnum.AND.getCode(), strategy.getConditionTypeEnum())) {
                Set<SystemTrafficPolicyVO> item = strategy.parse(andList, trafficPolicyStrategyDTO);
                log.info("allocationProject规则匹配,strategy:{},result:{}", JSONObject.toJSONString(systemTrafficPolicyVOList), JSONObject.toJSONString(item));
                if (CollectionUtil.isEmpty(item)) {
                    return ProjectCodeEnum.GX.getCode();
                }
                andList.retainAll(item);
            } else if (StrUtil.equals(ConditionTypeEnum.OR.getCode(), strategy.getConditionTypeEnum())) {
                Set<SystemTrafficPolicyVO> item = strategy.parse(orList, trafficPolicyStrategyDTO);
                log.info("allocationProject规则匹配,strategy:{},result:{}", JSONObject.toJSONString(systemTrafficPolicyVOList), JSONObject.toJSONString(item));
                if (CollectionUtil.isEmpty(item)) {
                    continue;
                }
                orListResult.addAll(item);
            }
        }
        log.info("allocationProject全部规则匹配的结果,AND:{},OR:{}", JSONObject.toJSONString(andList), JSONObject.toJSONString(orListResult));
        // 并集不存在 默认国学
        if (CollectionUtil.isEmpty(orListResult) || CollectionUtil.isEmpty(andList)) {
            return ProjectCodeEnum.GX.getCode();
        }

        andList.retainAll(orListResult);
        log.info("allocationProject满足条件的项目方,AND:{}", JSONObject.toJSONString(andList));
        if (CollectionUtil.isEmpty(andList)) {
            return ProjectCodeEnum.GX.getCode();
        } else if (andList.size() == 1) {
            return new ArrayList<>(andList).get(0).getProjectCode();
        } else {
            if (CollectionUtil.isEmpty(projectOrderNumMap)) {
                List<String> projectCode = andList.stream().map(SystemTrafficPolicyVO::getProjectCode).collect(Collectors.toList());
                LocalDateTime startTime = LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.now());
                List<ProjectOrderNumBO> projectOrderNum = systemOrderMapper.selectProjectOrderNum(projectCode, startTime);
                projectOrderNumMap = projectOrderNum.stream()
                        .collect(Collectors.toMap(ProjectOrderNumBO::getProjectCode, ProjectOrderNumBO::getCount, (k1, k2) -> k2));
            }
            return this.computeWeight(andList, projectOrderNumMap);
        }
    }

    public String computeWeight(Set<SystemTrafficPolicyVO> trafficPolicyVOSet, Map<String, Long> projectOrderNumMap) {
        log.info("computeWeight计算权重项目方当日订单量,projectOrderNumMap:{}", JSONObject.toJSONString(projectOrderNumMap));
        Map<String, Double> projectRateMap = new HashMap<>();
        double totalWeight = 0d;
        for (SystemTrafficPolicyVO systemTrafficPolicyVO : trafficPolicyVOSet) {
            // 达成率
            long orderNum = projectOrderNumMap.getOrDefault(systemTrafficPolicyVO.getProjectCode(), 0L);
            double achievementRate = orderNum / (systemTrafficPolicyVO.getDailyQuota() * PARAM_R);
            double weight = ((1 - achievementRate) * systemTrafficPolicyVO.getWeightCoefficient() * PARAM_K + PARAM_B);
            // 计算的权重可能 为负数,超额完成单量的情况，
            log.info("computeWeight计算的指标,orderNum:{},achievementRate:{},weight:{}", orderNum, achievementRate, weight);
            if (weight > 0) {
                projectRateMap.put(systemTrafficPolicyVO.getProjectCode(), weight);
                totalWeight = totalWeight + weight;
            }
        }

        // 有可能全部超额，就默认国学
        if (CollectionUtil.isEmpty(projectRateMap)) {
            return ProjectCodeEnum.GX.getCode();
        }

        // 生成随机数
        double randomValue = RandomUtil.randomDouble(totalWeight);
        log.info("computeWeight权重随机值,randomValue:{},projectRateMap:{}", randomValue, JSONObject.toJSONString(projectRateMap));
        // 遍历查找区间
        for (Map.Entry<String, Double> stringLongEntry : projectRateMap.entrySet()) {
            if (randomValue < stringLongEntry.getValue()) {
                return stringLongEntry.getKey();
            }
            randomValue -= stringLongEntry.getValue();
        }
        return ProjectCodeEnum.GX.getCode();
    }

    @Override
    public List<SystemTrafficPolicyVO> queryPolicyList() {
        return this.baseMapper.selectPolicyList();
    }
}